﻿//给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。
//如果 s 中不存在涵盖 t 所有字符的子串，则返回空字符串 "" 。
//
//注意：
//对于 t 中重复字符，我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
//如果 s 中存在这样的子串，我们保证它是唯一的答案。
//
//输入：s = "ADOBECODEBANC", t = "ABC"
//输出："BANC"
//解释：最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
//
//输入：s = "a", t = "a"
//输出："a"
//解释：整个字符串 s 是最小覆盖子串。
//
//输入: s = "a", t = "aa"
//输出 : ""
//解释 : t 中两个字符 'a' 均应包含在 s 的子串中，
//因此没有符合条件的子字符串，返回空字符串。
//
//提示：
//	m == s.length
//	n == t.length
//	1 <= m, n <= 10^5
//	s 和 t 由英文字母组成

class Solution {
public:
    string minWindow(string s, string t) {
        int hash1[128] = { 0 }; // 统计字符串t中每⼀个字符的频次

        int kinds = 0; // 统计有效字符有多少种

        for (auto ch : t)
            if (hash1[ch]++ == 0)
                kinds++;
        int hash2[128] = { 0 }; // 统计窗⼝内每个字符的频次

        int minlen = INT_MAX, begin = -1;
        for (int left = 0, right = 0, count = 0; right < s.size(); right++) {
            char in = s[right];
            if (++hash2[in] == hash1[in])
                count++;           // 进窗⼝+维护count
            while (count == kinds) // 判断条件

            {
                if (right - left + 1 < minlen) // 更新结果

                {
                    minlen = right - left + 1;
                    begin = left;
                }
                char out = s[left++];
                if (hash2[out]-- == hash1[out])
                    count--; // 出窗⼝+维护count
            }
        }
        if (begin == -1)
            return "";
        else
            return s.substr(begin, minlen);
    }
};